package com.it.flowable.service.leave.bpm;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.it.flowable.common.constants.BpmCommonConstant;
import com.it.flowable.common.constants.BpmLeaveConstant;
import com.it.flowable.common.vo.leave.LeaveBpmCreatTaskParamVO;
import com.it.flowable.common.vo.leave.LeaveBpmParamVO;
import com.it.flowable.entity.leave.*;
import com.it.flowable.mapper.leave.*;
import com.it.flowable.service.common.CommonUtils;
import liquibase.pro.packaged.U;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 请假流程数据库操作
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class BpmLeaveDao {

    @Autowired
    private ActFlwUserLeaveVOMapper actFlwUserLeaveVOMapper;
    @Autowired
    private ActFlwTaskLeaveVOMapper actFlwTaskLeaveVOMapper;
    @Autowired
    private ActFlwServiceDataLeaveVOMapper actFlwServiceDataLeaveVOMapper;
    @Autowired
    private ActLeaveProcessExtVOMapper actLeaveProcessExtVOMapper;
    @Autowired
    private ActFlwMainLeaveVOMapper actFlwMainLeaveVOMapper;
    @Autowired
    private ActFlwServiceDataRuLeaveVOMapper actFlwServiceDataRuLeaveVOMapper;
    @Resource
    private CommonUtils commonUtils;

    /** ====================== insert ======================= */
    /**
     * 主表信息插入
     */
    public ActFlwMainLeaveVO insertActFlwMainLeaveVO() {
        ActFlwMainLeaveVO mainLeaveVO = new ActFlwMainLeaveVO();
        mainLeaveVO.setCId(UUID.randomUUID().toString());
        mainLeaveVO.setCMainId(UUID.randomUUID().toString());
        mainLeaveVO.setCCaseState(BpmLeaveConstant.LEAVE_STATUS_INIT);
        mainLeaveVO.setTCrtTm(new Date());
        mainLeaveVO.setTUpdTm(new Date());
        actFlwMainLeaveVOMapper.insert(mainLeaveVO);
        return mainLeaveVO;
    }

    /**
     * 流程信息插入
     */
    public ActFlwTaskLeaveVO insertActFlwTaskLeaveVO(Map<String, Object> map) {
        ActFlwTaskLeaveVO taskLeaveVO = new ActFlwTaskLeaveVO();
        taskLeaveVO.setCId(commonUtils.createUUIDKey());
        taskLeaveVO.setCMainId(MapUtils.getString(map, "cMainId"));
        taskLeaveVO.setCTaskNo(commonUtils.createUUIDKey());
        taskLeaveVO.setCTaskType(MapUtils.getString(map, "cTaskType"));
        taskLeaveVO.setNTrackNum(BpmCommonConstant.NUMBER_1);
        taskLeaveVO.setCAppCde(MapUtils.getString(map, "cAppCde"));
        taskLeaveVO.setCAppRmk(MapUtils.getString(map, "cAppRmk"));
        taskLeaveVO.setCDays(MapUtils.getInteger(map, "cDays"));
        taskLeaveVO.setCFirstChkOpn(MapUtils.getString(map, "cFirstChkOpn"));
        taskLeaveVO.setCFirstChkCde(MapUtils.getString(map, "cFirstChkCde"));
        taskLeaveVO.setCFirstChkRmk(MapUtils.getString(map, "cFirstChkRmk"));
        taskLeaveVO.setCSecondChkOpn(MapUtils.getString(map, "cSecondChkOpn"));
        taskLeaveVO.setCSecondChkCde(MapUtils.getString(map, "cSecondChkCde"));
        taskLeaveVO.setCSecondChkRmk(MapUtils.getString(map, "cSecondChkRmk"));
        taskLeaveVO.setCNewFlg(BpmCommonConstant.IS_YES);
        taskLeaveVO.setIsReApply(BpmCommonConstant.IS_NO);
        taskLeaveVO.setIsCancelApply(BpmCommonConstant.IS_NO);
        taskLeaveVO.setTCrtTm(new Date());
        taskLeaveVO.setTUpdTm(new Date());
        actFlwTaskLeaveVOMapper.insert(taskLeaveVO);
        return taskLeaveVO;
    }

    /**
     * 工作流业务扩展表数据插入
     */
    public ActFlwServiceDataLeaveVO insertActFlwServiceDataVO(Map<String, Object> map, ActFlwTaskLeaveVO actFlwTaskVO) {
        ActFlwServiceDataLeaveVO actFlwServiceDataVO = new ActFlwServiceDataLeaveVO();
//        actFlwServiceDataVO.setCTaskId(MapUtils.getString(map, "cTaskId"));
        actFlwServiceDataVO.setCTaskId(commonUtils.createUUIDKey());// 可看下是否取工作流自动生成的taskId
        actFlwServiceDataVO.setCMainId(actFlwTaskVO.getCMainId());
        actFlwServiceDataVO.setCTaskNo(actFlwTaskVO.getCTaskNo());
        actFlwServiceDataVO.setCTaskType(actFlwTaskVO.getCTaskType());
        actFlwServiceDataVO.setCOwnerId(MapUtils.getString(map, "cOwnerId"));
        actFlwServiceDataVO.setCUserId(MapUtils.getString(map, "cUserId"));
        actFlwServiceDataVO.setCTaskKind(BpmLeaveConstant.LEAVE_STATUS_INIT);
        actFlwServiceDataVO.setCStatus(BpmLeaveConstant.LEAVE_STATUS_INIT);
        actFlwServiceDataVO.setTCrtTm(new Date());
        actFlwServiceDataVO.setTUpdTm(new Date());
        actFlwServiceDataLeaveVOMapper.insert(actFlwServiceDataVO);
        return actFlwServiceDataVO;
    }

    /**
     * 流程图数据表 插入
     */
    public void insertActLeaveProcessExtVO(String cProcessId, Map<String, Object> bpmParamMap) {
        LeaveBpmParamVO leaveBpmParamVO = (LeaveBpmParamVO) bpmParamMap.get("LeaveBpmParamVO");
        ActLeaveProcessExtVO processExtVO = new ActLeaveProcessExtVO();
        processExtVO.setCProcessId(cProcessId);
        processExtVO.setCProcessNme(BpmLeaveConstant.LEAVE_PROCESS_KEY);
        processExtVO.setCSupProcessId("");// 暂时置空，后面再扩展
        processExtVO.setCMainId(leaveBpmParamVO.getCMainId());
        processExtVO.setCStatus(BpmLeaveConstant.LEAVE_STATUS_INIT);
        processExtVO.setTCrtTm(new Date());
        actLeaveProcessExtVOMapper.insert(processExtVO);
    }
    public void insertActLeaveProcessExtVO(DelegateExecution execution) {
        ActLeaveProcessExtVO processExtVO = new ActLeaveProcessExtVO();
        ExecutionEntity ent = (ExecutionEntity) execution;
        Map<String, Object> bpmParamMap = ent.getVariables();
        LeaveBpmParamVO leaveBpmParamVO = (LeaveBpmParamVO) bpmParamMap.get("LeaveBpmParamVO");
        processExtVO.setCProcessId(commonUtils.createUUIDKey());
        processExtVO.setCProcessNme(BpmLeaveConstant.LEAVE_PROCESS_KEY);
        processExtVO.setCSupProcessId("");// 暂时置空，后面再扩展
        processExtVO.setCMainId(leaveBpmParamVO.getCMainId());
        processExtVO.setCStatus(BpmLeaveConstant.LEAVE_STATUS_INIT);
        processExtVO.setTCrtTm(new Date());
        actLeaveProcessExtVOMapper.insert(processExtVO);
    }

    /**
     * 业务扩展表新增
     */
    public ActFlwServiceDataLeaveVO initTaskExt(DelegateTask task, Map<String, Object> map) throws Exception{
        LeaveBpmParamVO leaveBpmParamVO = (LeaveBpmParamVO) map.get("LeaveBpmParamVO");
        log.info("initTaskExt leaveBpmParamVO >>> " + JSON.toJSONString(leaveBpmParamVO));
        if (leaveBpmParamVO == null) {
            throw new Exception("initTaskExt leaveBpmParamVO is null!");
        }
        LeaveBpmCreatTaskParamVO cBpmCreatTaskParamVO = leaveBpmParamVO.getCBpmCreatTaskParamVO();
        log.info("initTaskExt cBpmCreatTaskParamVO >>> " + JSON.toJSONString(cBpmCreatTaskParamVO));

        ActFlwServiceDataLeaveVO taskExtVO = new ActFlwServiceDataLeaveVO();
        taskExtVO.setCTaskId(task.getId()); // 任务ID
        taskExtVO.setCMainId(leaveBpmParamVO.getCMainId());
        taskExtVO.setCTaskKind(StringUtils.isNotEmpty(leaveBpmParamVO.getCTaskKind())?BpmCommonConstant.IS_NO:leaveBpmParamVO.getCTaskKind());
        taskExtVO.setCTaskNo(cBpmCreatTaskParamVO.getCTaskNo());
        taskExtVO.setCTaskType(cBpmCreatTaskParamVO.getCTaskType());
        taskExtVO.setCOwnerId(cBpmCreatTaskParamVO.getCOwnerId());
        taskExtVO.setCUserId(cBpmCreatTaskParamVO.getCUserId());
        taskExtVO.setCStatus(BpmLeaveConstant.LEAVE_STATUS_INIT);
        taskExtVO.setTCrtTm(new Date());
        taskExtVO.setTUpdTm(new Date());

        // 校验初始化参数
        this.checkInitParam(taskExtVO);

        actFlwServiceDataLeaveVOMapper.insert(taskExtVO);
        return taskExtVO;
    }

    public ActFlwServiceDataRuLeaveVO initTaskExtRu(ActFlwServiceDataLeaveVO taskExt) throws Exception{
        ActFlwServiceDataRuLeaveVO taskExtRu = new ActFlwServiceDataRuLeaveVO();
        BeanUtils.copyProperties(taskExt, taskExtRu);
        actFlwServiceDataRuLeaveVOMapper.insert(taskExtRu);

        return taskExtRu;
    }

    /** =================================== update ============================== */
    /**
     * 更新任务信息
     *
     * @param taskLeaveVO
     */
    public ActFlwTaskLeaveVO updateTaskLeave_Add(ActFlwTaskLeaveVO taskLeaveVO, Map<String, Object> reqMap) {
        // 更新原标识为0
        LambdaUpdateWrapper<ActFlwTaskLeaveVO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(ActFlwTaskLeaveVO::getCNewFlg, BpmCommonConstant.IS_NO)
                     .set(ActFlwTaskLeaveVO::getTUpdTm, new Date())
                     .eq(ActFlwTaskLeaveVO::getCId, taskLeaveVO.getCId());
        actFlwTaskLeaveVOMapper.update(null, updateWrapper);
        // 新增一条
        ActFlwTaskLeaveVO newTaskLeaveVO = new ActFlwTaskLeaveVO();
        BeanUtils.copyProperties(taskLeaveVO, newTaskLeaveVO);
        newTaskLeaveVO.setCId(commonUtils.createUUIDKey());
        newTaskLeaveVO.setCTaskNo(commonUtils.createUUIDKey());
        newTaskLeaveVO.setNTrackNum(taskLeaveVO.getNTrackNum() + 1);
        newTaskLeaveVO.setTCrtTm(new Date());
        newTaskLeaveVO.setTUpdTm(new Date());
        newTaskLeaveVO.setCTaskType(MapUtils.getString(reqMap, "cToTaskType"));
        newTaskLeaveVO.setCNewFlg(BpmCommonConstant.IS_YES);
        actFlwTaskLeaveVOMapper.insert(newTaskLeaveVO);

        return newTaskLeaveVO;
    }

    /**
     * 更新流程状态
     */
    public void updateActLeaveProcessExtVO(String cProcessId, String status) {
        ActLeaveProcessExtVO processExtVO = actLeaveProcessExtVOMapper.selectById(cProcessId);
        if (processExtVO != null) {
            processExtVO.setCStatus(status);
            actLeaveProcessExtVOMapper.updateById(processExtVO);
        }
    }
    /**
     * 更新已接收
     */
    public ActFlwServiceDataLeaveVO updateTaskExtByAccept(String taskId, String userId) throws Exception {
        if (StringUtils.isEmpty(taskId)) {
            throw new Exception("通过taskId更新任务扩展表相关信息失败：BpmLeaveDao.updateTaskExtByAccept，taskId任务ID为空，请联系管理员");
        }

        ActFlwServiceDataLeaveVO ext = actFlwServiceDataLeaveVOMapper.selectById(taskId);
        ext.setCStatus(BpmLeaveConstant.LEAVE_STATUS_ACCEPT);
        ext.setCOwnerId(userId);
        ext.setTUpdTm(new Date());
        ext.setTAcceptTm(new Date());
        actFlwServiceDataLeaveVOMapper.updateById(ext);
        return ext;
    }
    public ActFlwServiceDataRuLeaveVO updateTaskExtRuByAccept(String taskId, String userId) throws Exception {
        if (StringUtils.isEmpty(taskId)) {
            throw new Exception("通过taskId更新任务扩展表相关信息失败：BpmLeaveDao.updateTaskExtByAccept，taskId任务ID为空，请联系管理员");
        }

        ActFlwServiceDataRuLeaveVO ext = actFlwServiceDataRuLeaveVOMapper.selectById(taskId);
        ext.setCStatus(BpmLeaveConstant.LEAVE_STATUS_ACCEPT);
        ext.setCOwnerId(userId);
        ext.setTUpdTm(new Date());
        ext.setTAcceptTm(new Date());
        actFlwServiceDataRuLeaveVOMapper.updateById(ext);
        return ext;
    }
    /**
     * 更新已完成
     */
    public ActFlwServiceDataLeaveVO updateTaskExtByComplete(DelegateTask task) throws Exception {
        if (StringUtils.isEmpty(task.getId())) {
            throw new Exception("通过taskId更新任务扩展表相关信息失败：BpmLeaveDao.updateTaskExtByComplete，taskId任务ID为空，请联系管理员");
        }
        Map<String, Object> bpmParamMap = task.getVariables();
        LeaveBpmParamVO leaveBpmParamVO = (LeaveBpmParamVO) bpmParamMap.get("LeaveBpmParamVO");
        String userId = leaveBpmParamVO.getCOperCde();

        ActFlwServiceDataLeaveVO taskExt = actFlwServiceDataLeaveVOMapper.selectById(task.getId());
        taskExt.setCStatus(BpmLeaveConstant.LEAVE_STATUS_COMPLETE); // 已完成状态
        if (StringUtils.isEmpty(taskExt.getCOwnerId())) {
            taskExt.setCOwnerId(userId);
        }
        taskExt.setTUpdTm(new Date());
        taskExt.setTCompTm(new Date());
        actFlwServiceDataLeaveVOMapper.updateById(taskExt);
        return taskExt;
    }

    /** ============================ 删除 ============================= */
    public void deleteTaskExtRuVO(ActFlwServiceDataLeaveVO taskExt) {
        actFlwServiceDataRuLeaveVOMapper.deleteById(taskExt.getCTaskId());
    }

    /** ============================= 查询|校验 =========================== */
    /**
     * 查询用户信息
     */
    public ActFlwUserLeaveVO getActFlwUserVO(String cUserId, String cLevel) {
        LambdaQueryWrapper<ActFlwUserLeaveVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ActFlwUserLeaveVO::getCUserId, cUserId)
                .eq(StringUtils.isNotEmpty(cLevel), ActFlwUserLeaveVO::getCLevel, cLevel);
        List<ActFlwUserLeaveVO> actFlwUserVOS = actFlwUserLeaveVOMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(actFlwUserVOS)) {
            return actFlwUserVOS.get(0);
        } else {
            return null;
        }
    }

    /**
     * 获取审核人信息列表
     *
     * @param cUserId
     * @param cLevel
     * @return
     */
    public List<ActFlwUserLeaveVO> getActFlwCheckUserVO(String cUserId, String cLevel) throws Exception {
        LambdaQueryWrapper<ActFlwUserLeaveVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotEmpty(cUserId), ActFlwUserLeaveVO::getCUserId, cUserId)
                .eq(StringUtils.isNotEmpty(cLevel), ActFlwUserLeaveVO::getCLevel, cLevel);
        List<ActFlwUserLeaveVO> actFlwUserVOS = actFlwUserLeaveVOMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(actFlwUserVOS)) {
            return actFlwUserVOS;
        } else {
            throw new Exception("当前无此级别审批人，清先配置！");
        }
    }

    /**
     * 获取审核人
     *
     * @param cUserId
     * @param cLevel
     * @return
     * @throws Exception
     */
    public String getCheckCdeList(String cUserId, String cLevel) throws Exception {
        List<ActFlwUserLeaveVO> list = getActFlwCheckUserVO(cUserId, cLevel);
        List<String> collect = list.stream().map(e -> e.getCUserId()).collect(Collectors.toList());
        return String.join(",", collect);
    }

    /**
     * 审核人派工处理，随机分配
     */
    public ActFlwUserLeaveVO pgCheckCde(String cUserId, String cLevel) throws Exception {
        List<ActFlwUserLeaveVO> list = getActFlwCheckUserVO(cUserId, cLevel);
        int size = list.size();
        double v = Math.random() * size;
        int random = (int) v; // 向下取整，避免越界
        return list.get(random);
    }

    public List<ActFlwMainLeaveVO> getMainVOList(String cMainId, String cCaseState) {
        LambdaQueryWrapper<ActFlwMainLeaveVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ActFlwMainLeaveVO::getCMainId, cMainId)
                .eq(StringUtils.isNotEmpty(cCaseState), ActFlwMainLeaveVO::getCCaseState, cCaseState);
        return actFlwMainLeaveVOMapper.selectList(wrapper);
    }

    public ActFlwTaskLeaveVO getActFlwTaskLeaveVO(String cMainId, String cTaskType, String cTaskNo) {
        LambdaQueryWrapper<ActFlwTaskLeaveVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotEmpty(cMainId), ActFlwTaskLeaveVO::getCMainId, cMainId)
                .eq(StringUtils.isNotEmpty(cTaskNo), ActFlwTaskLeaveVO::getCTaskNo, cTaskNo)
                .eq(StringUtils.isNotEmpty(cTaskType), ActFlwTaskLeaveVO::getCTaskType, cTaskType)
                .eq(ActFlwTaskLeaveVO::getCNewFlg, BpmCommonConstant.IS_YES);
        List<ActFlwTaskLeaveVO> vos = actFlwTaskLeaveVOMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(vos)) {
            return null;
        }
        return vos.get(0);
    }

    /**
     * initTaskExt校验
     */
    public void checkInitParam(ActFlwServiceDataLeaveVO taskExtVO) throws Exception{
        if (StringUtils.isEmpty(taskExtVO.getCTaskNo())) {
            throw new Exception("checkInitParam cTaskNo is null!");
        }
        if (StringUtils.isEmpty(taskExtVO.getCTaskType())) {
            throw new Exception("checkInitParam cTaskType is null!");
        }
        if (StringUtils.isEmpty(taskExtVO.getCUserId())) {
            throw new Exception("checkInitParam cUserId is null!");
        }
    }


}
